<?php

namespace Sharks\Core\Http;

use InvalidArgumentException;
use Mobile_Detect;
use Sharks\Core\AppContext;
use Sharks\Core\Cfg\AppConfig;
use Sharks\Core\Http\Routing\RouteCaching;
use Sharks\Core\Http\Routing\RouteControl;
use Sharks\Core\Http\Routing\RouteResolve;
use Sharks\Core\Http\Routing\UrlRouteResolve;
use Sharks\Core\Support\Bag\ParameterBag;
use Sharks\Core\Support\Base\PropertiesReadOnly;
use Sharks\Core\Support\Log\Log;
use UnexpectedValueException;

/**
 * Http请求数据
 */
class Request {
    /**
     * HTTP方法
     */
    const METHOD_HEAD = 'HEAD';
    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';
    const METHOD_PUT = 'PUT';
    const METHOD_PATCH = 'PATCH';
    const METHOD_DELETE = 'DELETE';
    const METHOD_PURGE = 'PURGE';
    const METHOD_OPTIONS = 'OPTIONS';
    const METHOD_TRACE = 'TRACE';
    const METHOD_CONNECT = 'CONNECT';

    /** @app AppContext  */
    private $app;

    /**
     * request line
     * like: GET / HTTP/1.0
     * 'GET'        => @method
     * '/'          => @uri
     * 'HTTP/1.0'   => @httpVersion
     */
    /** @method http请求方法  */
    protected $httpVerb;

    /** @uri 请求路径  */
    protected $httpUri;

    /** @httpVersion http版本  */
    protected $httpVersion;

    /** @header 请求报文头  */
    protected $header;

    /** @var 查询字符串参数 */
    protected $query;

    /** @input REQUEST值  */
    protected $input;

    /** @var POST表单值 */
    protected $form;

    /** @route RouteResolveResult route解析结果  */
    protected $route;

    /** @var  浏览器类型 */
    protected $browserDetect;

    /**
     * 初始化Request
     * @param AppContext $app
     */
    public function __construct(AppContext $app) {
        $this->app = $app;
        $this->init();
    }

    /**
     * 初始化，生成Request数据
     * @return [type] [description]
     */
    protected function init() {
        $this->httpVerb = strtoupper($_SERVER['REQUEST_METHOD']);
        $this->httpUri = $_SERVER['REQUEST_URI'];
        $this->httpVersion = $_SERVER['SERVER_PROTOCOL'];

        $this->query = new ParameterBag($_GET);
        $this->form = new ParameterBag($_POST);
        $this->input = new ParameterBag($_REQUEST);
        $this->url = new Url;

        $this->initHeader();
        $this->initRoute();

        // 解析浏览器类型，判断是否移动端等
        $this->browserDetect = new Mobile_Detect;

        Log::debug("Request Initialzed");
        Log::debug("Request Path: " . $this->url->path);
        Log::debug("Request Device: " . ($this->browserDetect->isMobile() ? "Mobile" : "No Mobile"));
    }

    /**
     * 初始化请求头信息
     */
    protected function initHeader() {
        // init request header
        $header = array();
        if (!function_exists('getallheaders')) {
            foreach ($_SERVER as $name => $value) {
                if (substr($name, 0, 5) == 'HTTP_') {
                    $header[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
                }
            }
        }
        else {
            $header = getallheaders();
        }

        $this->header = new ParameterBag($header);
    }

    /**
     * 初始化route解析
     */
    protected function initRoute() {
        $routes = RouteControl::routes();
        $routeCaching = RouteCaching::instance();
        // 解析 route
        $this->route = (new RouteResolve($routes, $routeCaching, $this->url->path, $this->httpVerb))->resolve();
        $routeCaching->store();
    }

    use PropertiesReadOnly;

    private static $READ_ONLY = array('query', 'input', 'form', 'browserDetect', 'route', 'header', 'httpVerb', 'httpUri', 'httpVersion');
    private static $READ_ONLY_FUNC = array('ip');

    /**
     * http请求头
     * @param  [type] $name [description]
     * @return [type]       [description]
     */
    public function header($name) {
        return $this->header->get($name);
    }

    /**
     * $_GET 
     * @param  [type] $key     [description]
     * @param  [type] $default [description]
     * @return [type]          [description]
     */
    public function query($key, $default = null) {
        return $this->query->get($key, $default);
    }

    public function querys() {
        return $this->query->all();
    }

    /**
     * $_REQUEST
     * @param  [type] $key     [description]
     * @param  [type] $default [description]
     * @return [type]          [description]
     */
    public function input($key, $default = null) {
        return $this->input->get($key, $default);
    }

    public function inputs() {
        return $this->input->all();
    }

    /**
     * $_POST
     * @param  [type] $key     [description]
     * @param  [type] $default [description]
     * @return [type]          [description]
     */
    public function form($key, $default = null) {
        return $this->form->get($key, $default);
    }

    public function forms() {
        return $this->form->all();
    }

    public function isSecure() {
        return $this->app->server()->has('HTTPS');
    }

    public function userAgent() {
        return $this->app->server()->get('HTTP_USER_AGENT');
    }

    /**
     * referer
     * @return [type] [description]
     */
    public function referer() {
        return $this->app->server()->get('HTTP_REFERER');
    }

    /**
     * Returns the client IP address.
     * @return string
     */
    public function ip() {
        return $this->app->server()->get('REMOTE_ADDR');
    }

    /**
     * 判断是否是ajax
     * @return boolean [description]
     */
    public function isAjax() {
        if ($this->app->server()->has('HTTP_X_REQUESTED_WIDTH')) {
            if ('xmlhttprequest' == strtolower($this->app->server()->get('HTTP_X_REQUESTED_WIDTH'))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否http verb是否是POST
     * @return boolean [description]
     */
    public function isPost() {
        return $this->httpVerb == 'POST';
    }

    /**
     * 判断是否http verb是否是GET
     * @return boolean [description]
     */
    public function isGet() {
        return $this->httpVerb == 'GET';
    }

    /**
     * 浏览器侦测，请参考Mobile_Detect
     */
    public function browserDetect() {
        return $this->browserDetect;
    }

    public function app() {
        return $this->app;
    }

    public function url() {
        return $this->url;
    }

    public function route() {
        return $this->route;
    }

}